using System;
using System.Collections.Generic;
using System.Text;

namespace Com.Guocz.Media.FileSystem
{
    public class InputStream : AbstractInputStream
    {
        private Path path;
        private DataManager dataManager;

        private int blockCursor;
        private byte[] currentBuf;
        private int bufCursor;
        private Crypt.ICrypt cryptor;

        public InputStream(Path path, DataManager dataManager, Crypt.ICrypt cryptor)
        {
            this.path = path;
            this.dataManager = dataManager;
            this.cryptor = cryptor;

            blockCursor = 0;
            currentBuf = new byte[0];
            bufCursor = 0;
            currentBuf = cryptor.Decrypt(dataManager.read(path.BlockMetaList[0]));
        }

        private bool hasMore()
        {
            return countInBlock() > 0 || hasMoreBlock();
        }

        private bool hasMoreBlock()
        {
            return path.BlockMetaList.Count - 1 > blockCursor;
        }

        private int countInBlock()
        {
            return currentBuf.Length - bufCursor;
        }

        public override void Flush()
        {
            throw new InvalidOperationException("flush what?");
        }

        public override long Length
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        public override long Position
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        private void switchBlock()
        {
            if (hasMoreBlock())
            {
                currentBuf = cryptor.Decrypt(dataManager.read(path.BlockMetaList[++blockCursor]));
                bufCursor = 0;
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            int read = 0;
            while (count > 0)
            {
                if (!hasMore())
                {
                    return read;
                }
                if (countInBlock() == 0)
                {
                    switchBlock();
                }
                int current = Math.Min(count, countInBlock());
                System.Array.Copy(currentBuf, bufCursor, buffer, offset, current);
                offset += current;
                count -= current;
                bufCursor += current;
                read += current;
            }
            return read;
        }

        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override void SetLength(long value)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}
